package image.edge;

import image.processing.ImageProcessor;
import image.processing.ImageProcessor.CompressAlgorithm;
import image.utils.ImageUtilities;
import image.utils.ImageUtilitiesImpl;

import java.awt.image.BufferedImage;
import java.awt.image.WritableRaster;

public class SusanEdgeDetector extends EdgeDetectorImpl {

	public enum SUSAN_TYPES {CORNERS, BORDERS, BOTH, NONE}

	private static int[][] susanOperator = new int[7][7];
	private static boolean[][] susanOperatorCircle = {
			{ false, false, true, true, true, false, false },
			{ false, true, true, true, true, true, false },
			{ true, true, true, true, true, true, true },
			{ true, true, true, true, true, true, true },
			{ true, true, true, true, true, true, true },
			{ false, true, true, true, true, true, false },
			{ false, false, true, true, true, false, false }, };
	
	private int centerThreshold;
	private double tolerancia;
	private SUSAN_TYPES type;
	private boolean overImage;
/**
 * 	src imagen a aplicar
 * 	centerThrehold typical 27, but i did it variable
 * 	type border dection or corner detection or both
 * 	tolerancia mean the what approx means 0.5 +- 
 * @param src
 * @param centerThreshold
 * @param type
 * @param tolerancia
 */
	public SusanEdgeDetector(BufferedImage src,int centerThreshold, SUSAN_TYPES type, float tolerancia,boolean overImage) {
		super(src, 3);
		this.centerThreshold = centerThreshold;
		this.type = type;
		this.tolerancia = tolerancia;
		this.overImage = overImage;
	}

	@Override
	public BufferedImage FindEdges() {
		BufferedImage ans = null;
		if (src == null) {
			return null;
		} else {;
			if (src.getType() == BufferedImage.TYPE_BYTE_GRAY) {
				ImageUtilities utilimg = ImageUtilitiesImpl.getInstance();
				// BufferedImage extendedImage = extendImage(img, dimension /
				// 2);
				BufferedImage extendedImage = utilimg.addPaddingEdge(src,
						susanOperator.length / 2);
				if(overImage){
					ans = ImageUtilitiesImpl.getInstance().toRGB(src);	
				}else{
					ans = new BufferedImage(src.getWidth(), src.getHeight(),
						BufferedImage.TYPE_BYTE_GRAY);
				}
				
				WritableRaster ansRaster = ans.getRaster();
				for (int x = 0; x < src.getWidth(); x++) {
					for (int y = 0; y < src.getHeight(); y++) {
						int value;
						int[][] mask = susanOperator;
						for (int i = x, maskx = 0; i < x + mask.length; i++, maskx++) {
							for (int j = y, masky = 0; j < y + mask[0].length; j++, masky++) {
								value = extendedImage.getRaster()
										.getSample(i, j, 0);
								susanOperator[maskx][masky] = value;
							}
						}
						
						 int n = calculateNfromCenter();
						 double s = calculateS(n);
						 if(type == SUSAN_TYPES.BORDERS){
							 if(isBorder(s))
								 if(overImage){
									 ansRaster.setSample(x, y, 0, 0);
									 ansRaster.setSample(x, y, 1, 255);
									 ansRaster.setSample(x, y, 2, 0);
								 }else{
									 ansRaster.setSample(x, y, 0, 255);
								 }
							 else
								 if(!overImage)
									 ansRaster.setSample(x, y, 0, 0);
						 }else if(type == SUSAN_TYPES.CORNERS){
							 if(isCorner(s))
								 if(overImage){
									 ansRaster.setSample(x, y, 0, 0);
									 ansRaster.setSample(x, y, 1, 255);
									 ansRaster.setSample(x, y, 2, 0);
								 }else{
									 ansRaster.setSample(x, y, 0, 255);
								 }
							 else{
								 if(!overImage)
									 ansRaster.setSample(x, y, 0, 0);
							 }
						 }else{
							 if(isCorner(s) || isBorder(s)){
								 if(overImage){
									 ansRaster.setSample(x, y, 0, 0);
									 ansRaster.setSample(x, y, 1, 255);
									 ansRaster.setSample(x, y, 2, 0);
								 }else{
									 ansRaster.setSample(x, y, 0, 255);
								 }
							 }else{
								 if(!overImage)
								 ansRaster.setSample(x, y, 0, 0);
							 }
						 }
						//intValues[x][y] = value;
					}
				}
			}
		}
		return ans;

	}
	
	private int getCenterValue(){
		int centerx = susanOperator.length / 2;
		int centery = susanOperator[0].length / 2;
		return susanOperator[centerx][centery];
	}
	
	
	private int calculateNfromCenter(){
		int resp = 0;
		for(int i = 0; i < susanOperator.length; i++){
			for( int j = 0; j < susanOperator[i].length; j++){
				if(susanOperatorCircle[i][j]){
					if(Math.abs(susanOperator[i][j] - getCenterValue()) < centerThreshold){
						resp += 1;
					}
				}
			}
		}
		return resp;
	}
	
	private int susanCircleDimension(){
		int count = 0;
		for(int i = 0; i < susanOperator.length; i++){
			for( int j = 0; j < susanOperator[i].length; j++){
				if(susanOperatorCircle[i][j]){
						count += 1;
				}
			}
		}
		return count;
	}
	
	private double calculateS(int n){
		return 1 - (((double)n)/susanCircleDimension());
	}
	
	private boolean isBorder(double s){
		if(Math.abs(0.5d - s) < tolerancia){
			return true;
		}
		return false;
	}
	private boolean isCorner(double s){
		if(Math.abs(0.75d - s) < tolerancia){
			return true;
		}
		return false;
	}
}
